import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext, font

import ttkbootstrap as ttkb
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


@annotate(ClassInfo(name="文本查看", category="file"))
class TextView(View):
    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 当前打开的文件路径
        self.current_file = None

        # 查找相关变量
        self.find_window = None
        self.find_entry = None
        self.find_pos = 0

        # 字体相关设置
        self.current_font_size = 10
        self.font_families = sorted(font.families())
        self.current_font_family = "Consolas" if "Consolas" in self.font_families else self.font_families[0]

        # 创建UI
        self._create_widgets()

        # 配置文本框的撤销/重做功能
        self.text_area.config(undo=True)

        # 更新状态栏信息
        self.update_status()

        # 绑定事件
        self.bind_events()

    def _create_widgets(self):
        # 创建工具栏（包含所有功能按钮）
        self.create_toolbars()

        # 创建主内容区域（行号+文本编辑区）
        self.create_main_content()

        # 创建状态栏
        self.create_status_bar()

    def create_toolbars(self):
        # 创建主工具栏框架
        toolbar_frame = ttkb.Frame(self)
        toolbar_frame.pack(side=TOP, fill=X, padx=5, pady=5)

        # 文件操作工具栏
        file_toolbar = ttkb.LabelFrame(toolbar_frame, text="文件操作", padding=5)
        file_toolbar.pack(side=LEFT, padx=5)

        ttkb.Button(file_toolbar, text="新建", command=self.new_file, bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Button(file_toolbar, text="打开", command=self.open_file, bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Button(file_toolbar, text="保存", command=self.save_file, bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Button(file_toolbar, text="另存为", command=self.save_as_file, bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        # ttkb.Button(file_toolbar, text="退出", command=self.quit, bootstyle=DANGER).pack(side=LEFT, padx=2)

        # 编辑操作工具栏
        edit_toolbar = ttkb.LabelFrame(toolbar_frame, text="编辑操作", padding=5)
        edit_toolbar.pack(side=LEFT, padx=5)

        ttkb.Button(edit_toolbar, text="撤销", command=lambda: self.text_area.event_generate("<<Undo>>"),
                    bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Button(edit_toolbar, text="重做", command=lambda: self.text_area.event_generate("<<Redo>>"),
                    bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Separator(edit_toolbar, orient=VERTICAL).pack(side=LEFT, padx=2, fill=Y)
        ttkb.Button(edit_toolbar, text="剪切", command=lambda: self.text_area.event_generate("<<Cut>>"),
                    bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Button(edit_toolbar, text="复制", command=lambda: self.text_area.event_generate("<<Copy>>"),
                    bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Button(edit_toolbar, text="粘贴", command=lambda: self.text_area.event_generate("<<Paste>>"),
                    bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Separator(edit_toolbar, orient=VERTICAL).pack(side=LEFT, padx=2, fill=Y)
        ttkb.Button(edit_toolbar, text="查找", command=self.find_text, bootstyle=OUTLINE).pack(side=LEFT, padx=2)
        ttkb.Button(edit_toolbar, text="全选", command=lambda: self.text_area.tag_add("sel", "1.0", "end"),
                    bootstyle=OUTLINE).pack(side=LEFT, padx=2)

        # 字体设置工具栏
        font_toolbar = ttkb.LabelFrame(toolbar_frame, text="字体设置", padding=5)
        font_toolbar.pack(side=LEFT, padx=5)

        ttkb.Label(font_toolbar, text="字体:").pack(side=LEFT, padx=2)
        self.font_family_var = tk.StringVar(value=self.current_font_family)
        font_combobox = ttkb.Combobox(
            font_toolbar,
            textvariable=self.font_family_var,
            values=self.font_families,
            width=12,
            state="readonly"
        )
        font_combobox.pack(side=LEFT, padx=2)
        font_combobox.bind("<<ComboboxSelected>>", lambda e: self.change_font())

        ttkb.Label(font_toolbar, text="字号:").pack(side=LEFT, padx=2)
        self.font_size_var = tk.IntVar(value=self.current_font_size)
        ttkb.Button(font_toolbar, text="-", command=self.decrease_font_size, bootstyle=OUTLINE, width=2).pack(side=LEFT)
        ttkb.Label(font_toolbar, textvariable=self.font_size_var, width=3).pack(side=LEFT, padx=1)
        ttkb.Button(font_toolbar, text="+", command=self.increase_font_size, bootstyle=OUTLINE, width=2).pack(side=LEFT)

        # 视图设置工具栏
        view_toolbar = ttkb.LabelFrame(toolbar_frame, text="视图设置", padding=5)
        view_toolbar.pack(side=LEFT, padx=5)

        self.show_line_numbers = tk.BooleanVar(value=True)
        ttkb.Checkbutton(
            view_toolbar,
            text="显示行号",
            variable=self.show_line_numbers,
            command=self.update_line_numbers
        ).pack(side=LEFT, padx=5)

        ttkb.Button(view_toolbar, text="关于", command=self.show_about, bootstyle=INFO).pack(side=LEFT, padx=5)

        # 主题选择工具栏
        theme_toolbar = ttkb.LabelFrame(toolbar_frame, text="主题", padding=5)
        theme_toolbar.pack(side=LEFT, padx=5)

        self.selected_theme = tk.StringVar(value="litera")
        theme_combobox = ttkb.Combobox(
            theme_toolbar,
            textvariable=self.selected_theme,
            values=ttkb.Style().theme_names(),
            width=12,
            state="readonly"
        )
        theme_combobox.pack(side=LEFT, padx=2)
        theme_combobox.bind("<<ComboboxSelected>>", lambda e: self.change_theme())

    def create_main_content(self):
        # 创建主框架
        main_frame = ttkb.Frame(self)
        main_frame.pack(fill=BOTH, expand=True, padx=5, pady=5)

        # 行号区域
        self.line_numbers = tk.Text(main_frame, width=5, padx=5, takefocus=0, border=0,
                                    state=tk.DISABLED,
                                    font=(self.current_font_family, self.current_font_size))
        self.line_numbers.pack(side=LEFT, fill=Y)

        # 文本编辑区域
        self.text_area = scrolledtext.ScrolledText(
            main_frame,
            wrap=tk.WORD,
            font=(self.current_font_family, self.current_font_size),
            undo=True
        )
        self.text_area.pack(side=LEFT, fill=BOTH, expand=True)

        # 绑定文本变化事件以更新行号
        self.text_area.bind("<<Modified>>", self.update_line_numbers)
        self.text_area.bind("<KeyRelease>", self.update_status)
        self.text_area.bind("<ButtonRelease-1>", self.update_status)

    def create_status_bar(self):
        self.status_bar = ttkb.Label(self, text="行: 1 | 字符: 0", anchor=W)
        self.status_bar.pack(side=BOTTOM, fill=X)

    def bind_events(self):
        # 绑定快捷键
        self.bind("<Control-n>", lambda event: self.new_file())
        self.bind("<Control-o>", lambda event: self.open_file())
        self.bind("<Control-s>", lambda event: self.save_file())
        self.bind("<Control-Shift-S>", lambda event: self.save_as_file())
        self.bind("<Control-q>", lambda event: self.quit())
        self.bind("<Control-f>", lambda event: self.find_text())
        self.bind("<Control-a>", lambda event: self.text_area.tag_add("sel", "1.0", "end"))
        # 字体大小快捷键
        # self.bind("<Control-Plus>", lambda event: self.increase_font_size())
        # self.bind("<Control-Minus>", lambda event: self.decrease_font_size())
        self.bind("<Control-0>", lambda event: self.reset_font_size())

    def update_line_numbers(self, event=None):
        if not self.show_line_numbers.get():
            self.line_numbers.pack_forget()
            return
        elif not self.line_numbers.winfo_ismapped():
            self.line_numbers.pack(side=LEFT, fill=Y)

        # 获取文本框内容的行数
        lines = self.text_area.get("1.0", tk.END).count("\n") + 1

        # 更新行号
        self.line_numbers.config(state=tk.NORMAL)
        self.line_numbers.delete("1.0", tk.END)
        self.line_numbers.insert("1.0", "\n".join(str(i) for i in range(1, lines + 1)))
        self.line_numbers.config(state=tk.DISABLED)

    def update_status(self, event=None):
        # 获取当前光标位置
        position = self.text_area.index(tk.INSERT)
        line, column = position.split('.')

        # 计算总字符数（不包括最后一个换行符）
        text = self.text_area.get("1.0", tk.END)
        char_count = len(text.rstrip('\n'))

        # 更新状态栏
        self.status_bar.config(text=f"行: {line} | 列: {column} | 字符数: {char_count}")

    def increase_font_size(self):
        """增大字体大小"""
        if self.current_font_size < 24:  # 最大字号限制
            self.current_font_size += 1
            self.font_size_var.set(self.current_font_size)
            self.change_font()

    def decrease_font_size(self):
        """减小字体大小"""
        if self.current_font_size > 8:  # 最小字号限制
            self.current_font_size -= 1
            self.font_size_var.set(self.current_font_size)
            self.change_font()

    def reset_font_size(self):
        """重置字体大小为默认值"""
        self.current_font_size = 10
        self.font_size_var.set(self.current_font_size)
        self.change_font()

    def change_font(self):
        """更改字体或字号"""
        self.current_font_family = self.font_family_var.get()
        new_font = (self.current_font_family, self.current_font_size)

        # 更新文本区域字体
        self.text_area.configure(font=new_font)

        # 更新行号区域字体
        self.line_numbers.configure(font=new_font)

        # 重新计算行号
        self.update_line_numbers()

    def new_file(self):
        # 询问是否保存当前文件
        if self.text_area.edit_modified():
            response = messagebox.askyesnocancel("保存", "是否保存当前文件?")
            if response is None:  # 取消
                return
            if response:  # 是
                if not self.save_file():
                    return

        # 清空文本框
        self.text_area.delete("1.0", tk.END)
        self.current_file = None
        # self.title("文本编辑器")
        self.text_area.edit_modified(False)

    def open_file(self):
        # 询问是否保存当前文件
        if self.text_area.edit_modified():
            response = messagebox.askyesnocancel("保存", "是否保存当前文件?")
            if response is None:  # 取消
                return
            if response:  # 是
                if not self.save_file():
                    return

        # 打开文件对话框
        file_path = filedialog.askopenfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )

        if file_path:
            try:
                with open(file_path, "r", encoding="utf-8") as file:
                    content = file.read()
                    self.text_area.delete("1.0", tk.END)
                    self.text_area.insert("1.0", content)

                self.current_file = file_path
                # self.title(f"文本编辑器 - {os.path.basename(file_path)}")
                self.text_area.edit_modified(False)
            except Exception as e:
                messagebox.showerror("错误", f"无法打开文件: {str(e)}")

    def save_file(self):
        if self.current_file:
            try:
                content = self.text_area.get("1.0", tk.END)
                with open(self.current_file, "w", encoding="utf-8") as file:
                    file.write(content)

                # self.title(f"文本编辑器 - {os.path.basename(self.current_file)}")
                self.text_area.edit_modified(False)
                return True
            except Exception as e:
                messagebox.showerror("错误", f"无法保存文件: {str(e)}")
                return False
        else:
            return self.save_as_file()

    def save_as_file(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )

        if file_path:
            self.current_file = file_path
            return self.save_file()
        return False

    def find_text(self):
        # 如果查找窗口已存在，则激活它
        if self.find_window and self.find_window.winfo_exists():
            self.find_window.lift()
            self.find_entry.focus_set()
            return

        # 创建查找窗口
        self.find_window = ttkb.Toplevel(self)
        self.find_window.title("查找")
        self.find_window.geometry("300x100")
        self.find_window.resizable(False, False)
        self.find_window.transient(self)  # 设置为主窗口的子窗口
        self.find_window.grab_set()  # 模态窗口

        # 创建查找框
        frame = ttkb.Frame(self.find_window, padding=10)
        frame.pack(fill=BOTH, expand=True)

        ttkb.Label(frame, text="查找内容:").grid(row=0, column=0, sticky=W, pady=5)

        self.find_entry = ttkb.Entry(frame, width=25)
        self.find_entry.grid(row=0, column=1, pady=5, padx=5)
        self.find_entry.focus_set()

        # 查找按钮
        btn_frame = ttkb.Frame(frame)
        btn_frame.grid(row=1, column=0, columnspan=2, pady=10)

        ttkb.Button(btn_frame, text="查找下一个", command=self.find_next).pack(side=LEFT, padx=5)
        ttkb.Button(btn_frame, text="取消", command=self.find_window.destroy).pack(side=LEFT, padx=5)

        # 绑定Enter键
        self.find_window.bind("<Return>", lambda event: self.find_next())

    def find_next(self):
        # 获取要查找的文本
        search_text = self.find_entry.get()
        if not search_text:
            return

        # 获取文本框内容
        text = self.text_area.get("1.0", tk.END)

        # 从当前位置开始查找
        start_pos = f"1.0 + {self.find_pos} chars"
        start_index = self.text_area.index(start_pos)

        # 查找文本
        start = self.text_area.search(search_text, start_index, stopindex=tk.END)

        if start:
            # 计算结束位置
            end = f"{start}+{len(search_text)}c"

            # 清除之前的标记
            self.text_area.tag_remove("search", "1.0", tk.END)

            # 添加新标记并高亮显示
            self.text_area.tag_add("search", start, end)
            self.text_area.tag_config("search", background="yellow", foreground="black")

            # 滚动到找到的位置
            self.text_area.mark_set(tk.INSERT, end)
            self.text_area.see(start)

            # 更新查找位置
            self.find_pos = int(self.text_area.index(end).split('.')[1])
        else:
            # 如果没找到，从头开始
            messagebox.showinfo("查找", f"找不到 '{search_text}'")
            self.find_pos = 0

    def change_theme(self):
        # 更改应用主题
        theme = self.selected_theme.get()
        style = ttkb.Style()
        style.theme_use(theme)

        # 更新行号背景色以匹配新主题
        self.line_numbers.config(background=self.cget("bg"))

    def show_about(self):
        messagebox.showinfo(
            "关于",
            "文本编辑器 v1.1\n\n一个简单的文本编辑器，基于ttkbootstrap构建。\n支持打开、保存、查找、撤销、重做、字体调整等功能。"
        )

    def create_widgets(self):
        pass
